home *** CD-ROM | disk | FTP | other *** search
/ Internet Surfer 2.0 / Internet Surfer 2.0 (Wayzata Technology) (1996).iso / pc / text / mac / faqs.537 < prev    next >
Text File  |  1996-02-12  |  28KB  |  754 lines

  1. Frequently Asked Questions (FAQS);faqs.537
  2.  
  3.  
  4.  
  5.       In order to get your login shell to execute the script (without
  6.       forking) you have to use the "." command (for the Bourne or Korn
  7.       shells) or the "source" command (for the C shell).  I.e. you type
  8.  
  9.     . myscript
  10.  
  11.       to the Bourne or Korn shells, or
  12.  
  13.     source myscript
  14.  
  15.       to the C shell.
  16.  
  17.       If all you are trying to do is change directory or set an
  18.       environment variable, it will probably be simpler to use a C
  19.       shell alias or Bourne/Korn shell function.  See the "how do I get
  20.       the current directory into my prompt" section of this article for
  21.       some examples.
  22.  
  23. 2.9)  How do I redirect stdout and stderr separately in csh?
  24.  
  25.       In csh, you can redirect stdout with ">", or stdout and stderr
  26.       together with ">&" but there is no direct way to redirect stderr
  27.       only.  The best you can do is
  28.  
  29.     ( command >stdout_file ) >&stderr_file
  30.  
  31.       which runs "command" in a subshell;  stdout is redirected inside
  32.       the subshell to stdout_file, and both stdout and stderr from the
  33.       subshell are redirected to stderr_file, but by this point stdout
  34.       has already been redirected so only stderr actually winds up in
  35.       stderr_file.
  36.  
  37.       If what you want is to avoid redirecting stdout at all, let sh
  38.       do it for you.
  39.  
  40.     sh -c 'command 2>stderr_file'
  41.  
  42. 2.10) How do I tell inside .cshrc if I'm a login shell?
  43.  
  44.       From: msb@sq.com (Mark Brader)
  45.       Date: Mon, 26 Oct 1992 20:15:00 -0500
  46.  
  47.       When people ask this, they usually mean either
  48.  
  49.     How can I tell if it's an interactive shell?  or
  50.     How can I tell if it's a top-level shell?
  51.  
  52.       You could perhaps determine if your shell truly is a login shell
  53.       (i.e. is going to source ".login" after it is done with ".cshrc")
  54.       by fooling around with "ps" and "$$".  Login shells generally
  55.       have names that begin with a '-'.  If you're really interested in
  56.       the other two questions, here's one way you can organize your
  57.       .cshrc to find out.
  58.  
  59.     if (! $?CSHLEVEL) then
  60.         #
  61.         # This is a "top-level" shell,
  62.         # perhaps a login shell, perhaps a shell started up by
  63.         # 'rsh machine some-command'
  64.         # This is where we should set PATH and anything else we
  65.         # want to apply to every one of our shells.
  66.         #
  67.         setenv      CSHLEVEL        0
  68.         set home = ~username        # just to be sure
  69.         source ~/.env               # environment stuff we always want
  70.     else
  71.         #
  72.         # This shell is a child of one of our other shells so
  73.         # we don't need to set all the environment variables again.
  74.         #
  75.         set tmp = $CSHLEVEL
  76.         @ tmp++
  77.         setenv      CSHLEVEL        $tmp
  78.     endif
  79.  
  80.     # Exit from .cshrc if not interactive, e.g. under rsh
  81.     if (! $?prompt) exit
  82.  
  83.     # Here we could set the prompt or aliases that would be useful
  84.     # for interactive shells only.
  85.  
  86.     source ~/.aliases
  87.  
  88. 2.11) How do I construct a shell glob-pattern that matches all files
  89.       except "." and ".." ?
  90.  
  91.       You'd think this would be easy.
  92.  
  93.       *        Matches all files that don't begin with a ".";
  94.  
  95.       .*         Matches all files that do begin with a ".", but
  96.          this includes the special entries "." and "..",
  97.          which often you don't want;
  98.  
  99.       .[!.]*   (Newer shells only; some shells use a "^" instead of
  100.          the "!"; POSIX shells must accept the "!", but may
  101.          accept a "^" as well; all portable applications shall
  102.          not use an unquoted "^" immediately following the "[")
  103.  
  104.          Matches all files that begin with a "." and are
  105.          followed by a non-"."; unfortunately this will miss
  106.          "..foo";
  107.  
  108.       .??*     Matches files that begin with a "." and which are
  109.          at least 3 characters long.  This neatly avoids
  110.          "." and "..", but also misses ".a" .
  111.  
  112.       So to match all files except "." and ".." safely you have to use
  113.       3 patterns (if you don't have filenames like ".a" you can leave
  114.       out the first):
  115.  
  116.     .[!.]* .??* *
  117.  
  118.       Alternatively you could employ an external program or two and use
  119.       backquote substitution.  This is pretty good:
  120.  
  121.       `ls -a | sed -e '/^\.$/d' -e '/^\.\.$/d'`
  122.  
  123.     (or `ls -A` in some Unix versions)
  124.  
  125.       but even it will mess up on files with newlines, IFS characters
  126.       or wildcards in their names.
  127.  
  128. 2.12) How do I find the last argument in a Bourne shell script?
  129.  
  130.       Answer by:
  131.     Martin Weitzel <@mikros.systemware.de:martin@mwtech.uucp>
  132.     Maarten Litmaath <maart@nat.vu.nl>
  133.  
  134.       If you are sure the number of arguments is at most 9, you can use:
  135.  
  136.     eval last=\${$#}
  137.  
  138.       In POSIX-compatible shells it works for ANY number of arguments.
  139.       The following works always too:
  140.  
  141.     for last
  142.     do
  143.         :
  144.     done
  145.  
  146.       This can be generalized as follows:
  147.  
  148.     for i
  149.     do
  150.         third_last=$second_last
  151.         second_last=$last
  152.         last=$i
  153.     done
  154.  
  155.       Now suppose you want to REMOVE the last argument from the list,
  156.       or REVERSE the argument list, or ACCESS the N-th argument
  157.       directly, whatever N may be.  Here is a basis of how to do it,
  158.       using only built-in shell constructs, without creating subprocesses:
  159.  
  160.     t0= u0= rest='1 2 3 4 5 6 7 8 9' argv=
  161.  
  162.     for h in '' $rest
  163.     do
  164.         for t in "$t0" $rest
  165.         do
  166.             for u in $u0 $rest
  167.             do
  168.                 case $# in
  169.                 0)
  170.                     break 3
  171.                 esac
  172.                 eval argv$h$t$u=\$1
  173.                 argv="$argv \"\$argv$h$t$u\""    # (1)
  174.                 shift
  175.             done
  176.             u0=0
  177.         done
  178.         t0=0
  179.     done
  180.  
  181.     # now restore the arguments
  182.     eval set x "$argv"                    # (2)
  183.     shift
  184.  
  185.       This example works for the first 999 arguments.  Enough?
  186.       Take a good look at the lines marked (1) and (2) and convince
  187.       yourself that the original arguments are restored indeed, no
  188.       matter what funny characters they contain!
  189.  
  190.       To find the N-th argument now you can use this:
  191.  
  192.     eval argN=\$argv$N
  193.  
  194.       To reverse the arguments the line marked (1) must be changed to:
  195.  
  196.     argv="\"\$argv$h$t$u\" $argv"
  197.  
  198.       How to remove the last argument is left as an exercise.
  199.  
  200.       If you allow subprocesses as well, possibly executing nonbuilt-in
  201.       commands, the `argvN' variables can be set up more easily:
  202.  
  203.     N=1
  204.  
  205.     for i
  206.     do
  207.         eval argv$N=\$i
  208.         N=`expr $N + 1`
  209.     done
  210.  
  211.       To reverse the arguments there is still a simpler method, that
  212.       even does not create subprocesses.  This approach can also be
  213.       taken if you want to delete e.g. the last argument, but in that
  214.       case you cannot refer directly to the N-th argument any more,
  215.       because the `argvN' variables are set up in reverse order:
  216.  
  217.     argv=
  218.  
  219.     for i
  220.     do
  221.         eval argv$#=\$i
  222.         argv="\"\$argv$#\" $argv"
  223.         shift
  224.     done
  225.  
  226.     eval set x "$argv"
  227.     shift
  228.  
  229. 2.13) What's wrong with having '.' in your $PATH ?
  230.  
  231.       A bit of background: the PATH environment variable is a list of
  232.       directories separated by colons.  When you type a command name
  233.       without giving an explicit path (e.g. you type "ls", rather than
  234.       "/bin/ls") your shell searches each directory in the PATH list in
  235.       order, looking for an executable file by that name, and the shell
  236.       will run the first matching program it finds.
  237.  
  238.       One of the directories in the PATH list can be the current
  239.       directory "." .  It is also permissible to use an empty directory
  240.       name in the PATH list to indicate the current directory.  Both of
  241.       these are equivalent
  242.  
  243.       for csh users:
  244.  
  245.     setenv PATH :/usr/ucb:/bin:/usr/bin
  246.     setenv PATH .:/usr/ucb:/bin:/usr/bin
  247.  
  248.       for sh or ksh users
  249.  
  250.     PATH=:/usr/ucb:/bin:/usr/bin export PATH
  251.     PATH=.:/usr/ucb:/bin:/usr/bin export PATH
  252.  
  253.       Having "." somewhere in the PATH is convenient - you can type
  254.       "a.out" instead of "./a.out" to run programs in the current
  255.       directory.  But there's a catch.
  256.  
  257.       Consider what happens in the case  where "." is the first entry
  258.       in the PATH.  Suppose your current directory is a publically-
  259.       writable one, such as "/tmp".  If there just happens to be a
  260.       program named "/tmp/ls" left there by some other user, and you
  261.       type "ls" (intending, of course, to run the normal "/bin/ls"
  262.       program), your shell will instead run "./ls", the other user's
  263.       program.  Needless to say, the results of running an unknown
  264.       program like this might surprise you.
  265.  
  266.       It's slightly better to have "." at the end of the PATH:
  267.  
  268.     setenv PATH /usr/ucb:/bin:/usr/bin:.
  269.  
  270.       Now if you're in /tmp and you type "ls", the shell will
  271.       search /usr/ucb, /bin and /usr/bin for a program named
  272.       "ls" before it gets around to looking in ".", and there
  273.       is less risk of inadvertently running some other user's
  274.       "ls" program.  This isn't 100% secure though - if you're
  275.       a clumsy typist and some day type "sl -l" instead of "ls -l",
  276.       you run the risk of running "./sl", if there is one.
  277.       Some "clever" programmer could anticipate common typing
  278.       mistakes and leave programs by those names scattered
  279.       throughout public directories.  Beware.
  280.  
  281.       Many seasoned Unix users get by just fine without having
  282.       "." in the PATH at all:
  283.  
  284.     setenv PATH /usr/ucb:/bin:/usr/bin
  285.  
  286.       If you do this, you'll need to type "./program" instead
  287.       of "program" to run programs in the current directory, but
  288.       the increase in security is probably worth it.
  289.  
  290. --
  291. Ted Timar - tmatimar@empress.com
  292. Empress Software, 3100 Steeles Ave E, Markham, Ont., Canada L3R 8T3
  293. Xref: bloom-picayune.mit.edu comp.unix.questions:51335 comp.unix.shell:8341 news.answers:4777
  294. Path: bloom-picayune.mit.edu!senator-bedfellow.mit.edu!senator-bedfellow.mit.edu!usenet
  295. From: tmatimar@empress.com (Ted M A Timar)
  296. Newsgroups: comp.unix.questions,comp.unix.shell,news.answers
  297. Subject: Unix - Frequently Asked Questions (3/7) [Frequent posting]
  298. Supersedes: <unix-faq/faq/part3_723967331@athena.mit.edu>
  299. Followup-To: comp.unix.questions
  300. Date: 24 Dec 1992 06:03:13 GMT
  301. Organization: Empress Software
  302. Lines: 636
  303. Approved: news-answers-request@MIT.Edu
  304. Distribution: world
  305. Expires: 21 Jan 1993 06:02:09 GMT
  306. Message-ID: <unix-faq/faq/part3_725176929@athena.mit.edu>
  307. References: <unix-faq/faq/contents_725176929@athena.mit.edu>
  308. NNTP-Posting-Host: pit-manager.mit.edu
  309. X-Last-Updated: 1992/12/09
  310.  
  311. Archive-name: unix-faq/faq/part3
  312. Version: $Id: part3,v 2.1 92/12/04 07:43:49 tmatimar Exp $
  313.  
  314. These seven articles contain the answers to some Frequently Asked
  315. Questions often seen in comp.unix.questions and comp.unix.shell.
  316. Please don't ask these questions again, they've been answered plenty
  317. of times already - and please don't flame someone just because they may
  318. not have read this particular posting.  Thank you.
  319.  
  320. These articles are divided approximately as follows:
  321.  
  322.       1.*) General questions.
  323.       2.*) Relatively basic questions, likely to be asked by beginners.
  324.       3.*) Intermediate questions.
  325.       4.*) Advanced questions, likely to be asked by people who thought
  326.        they already knew all of the answers.
  327.       5.*) Questions pertaining to the various shells, and the differences.
  328.       6.*) An overview of Unix variants.
  329.       7.*) An comparison of configuration management systems (RCS, SCCS).
  330.  
  331. This article includes answers to:
  332.  
  333.       3.1)  How do I find out the creation time of a file?
  334.       3.2)  How do I use "rsh" without having the rsh hang around
  335.               until the remote command has completed?
  336.       3.3)  How do I truncate a file?
  337.       3.4)  Why doesn't find's "{}" symbol do what I want?
  338.       3.5)  How do I set the permissions on a symbolic link?
  339.       3.6)  How do I "undelete" a file?
  340.       3.7)  How can a process detect if it's running in the background?
  341.       3.8)  Why doesn't redirecting a loop work as intended?  (Bourne shell)
  342.       3.9)  How do I run 'passwd', 'ftp', 'telnet', 'tip' and other interactive
  343.               programs from a shell script or in the background?
  344.       3.10) How do I find out the process ID of a program with a particular
  345.             name from inside a shell script or C program?
  346.       3.11) How do I check the exit status of a remote command
  347.             executed via "rsh" ?
  348.       3.12) Is it possible to pass shell variable settings into an awk program?
  349.       3.13) How do I get rid of zombie processes that persevere?
  350.       3.14) How do I get lines from a pipe as they are written instead of
  351.             only in larger blocks.
  352.  
  353. If you're looking for the answer to, say, question 3.5, and want to skip
  354. everything else, you can search ahead for the regular expression "^3.5)".
  355.  
  356. While these are all legitimate questions, they seem to crop up in
  357. comp.unix.questions or comp.unix.shell on an annual basis, usually
  358. followed by plenty of replies (only some of which are correct) and then
  359. a period of griping about how the same questions keep coming up.  You
  360. may also like to read the monthly article "Answers to Frequently Asked
  361. Questions" in the newsgroup "news.announce.newusers", which will tell
  362. you what "UNIX" stands for.
  363.  
  364. With the variety of Unix systems in the world, it's hard to guarantee
  365. that these answers will work everywhere.  Read your local manual pages
  366. before trying anything suggested here.  If you have suggestions or
  367. corrections for any of these answers, please send them to to
  368. tmatimar@empress.com.
  369.  
  370. 3.1)  How do I find out the creation time of a file?
  371.  
  372.       You can't - it isn't stored anywhere.  Files have a last-modified
  373.       time (shown by "ls -l"), a last-accessed time (shown by "ls -lu")
  374.       and an inode change time (shown by "ls -lc"). The latter is often
  375.       referred to as the "creation time" - even in some man pages -
  376.       but that's wrong; it's also set by such operations as mv, ln,
  377.       chmod, chown and chgrp.
  378.  
  379.       The man page for "stat(2)" discusses this.
  380.  
  381. 3.2)  How do I use "rsh" without having the rsh hang around until the
  382.       remote command has completed?
  383.  
  384.       (See note in question 2.7 about what "rsh" we're talking about.)
  385.  
  386.       The obvious answers fail:
  387.               rsh machine command &
  388.       or      rsh machine 'command &'
  389.  
  390.       For instance, try doing   rsh machine 'sleep 60 &' and you'll see
  391.       that the 'rsh' won't exit right away.  It will wait 60 seconds
  392.       until the remote 'sleep' command finishes, even though that
  393.       command was started in the background on the remote machine.  So
  394.       how do you get the 'rsh' to exit immediately after the 'sleep' is
  395.       started?
  396.  
  397.       The solution - if you use csh on the remote machine:
  398.  
  399.         rsh machine -n 'command >&/dev/null </dev/null &'
  400.  
  401.       If you use sh on the remote machine:
  402.  
  403.         rsh machine -n 'command >/dev/null 2>&1 </dev/null &'
  404.  
  405.       Why?  "-n" attaches rsh's stdin to /dev/null so you could run the
  406.       complete rsh command in the background on the LOCAL machine.
  407.       Thus "-n" is equivalent to another specific "< /dev/null".
  408.       Furthermore, the input/output redirections on the REMOTE machine
  409.       (inside the single quotes) ensure that rsh thinks the session can
  410.       be terminated (there's no data flow any more.)
  411.  
  412.       Note: The file that you redirect to/from on the remote machine
  413.       doesn't have to be /dev/null; any ordinary file will do.
  414.  
  415.       In many cases, various parts of these complicated commands
  416.       aren't necessary.
  417.  
  418. 3.3)  How do I truncate a file?
  419.  
  420.       The BSD function ftruncate() sets the length of a file.  Xenix -
  421.       and therefore SysV r3.2 and later - has the chsize() system
  422.       call.  For other systems, the only kind of truncation you can do
  423.       is truncation to length zero with creat() or open(..., O_TRUNC).
  424.  
  425. 3.4)  Why doesn't find's "{}" symbol do what I want?
  426.  
  427.       "find" has a -exec option that will execute a particular command
  428.       on all the selected files. Find will replace any "{}" it sees
  429.       with the name of the file currently under consideration.
  430.  
  431.       So, some day you might try to use "find" to run a command on
  432.       every file, one directory at a time.  You might try this:
  433.  
  434.     find /path -type d -exec command {}/\* \;
  435.  
  436.       hoping that find will execute, in turn
  437.  
  438.     command directory1/*
  439.     command directory2/*
  440.     ...
  441.  
  442.       Unfortunately, find only expands the "{}" token when it appears
  443.       by itself.  Find will leave anything else like "{}/*" alone, so
  444.       instead of doing what you want, it will do
  445.  
  446.     command {}/*
  447.     command {}/*
  448.     ...
  449.  
  450.       once for each directory.  This might be a bug, it might be a
  451.       feature, but we're stuck with the current behaviour.
  452.  
  453.       So how do you get around this?  One way would be to write a
  454.       trivial little shell script, let's say "./doit", that consists of
  455.  
  456.     command "$1"/*
  457.  
  458.       You could then use
  459.  
  460.     find /path -type d -exec ./doit {} \;
  461.  
  462.       Or if you want to avoid the "./doit" shell script, you can use
  463.  
  464.     find /path -type d -exec sh -c 'command $0/*' {} \;
  465.  
  466.       (This works because within the 'command' of "sh -c 'command' A B C ...",
  467.        $0 expands to A, $1 to B, and so on.)
  468.  
  469.       or you can use the construct-a-command-with-sed trick
  470.  
  471.     find /path -type d -print | sed 's:.*:command &/*:' | sh
  472.  
  473.       If all you're trying to do is cut down on the number of times
  474.       that "command" is executed, you should see if your system has the
  475.       "xargs" command.  Xargs reads arguments one line at a time from
  476.       the standard input and assembles as many of them as will fit into
  477.       one command line.  You could use
  478.  
  479.     find /path -print | xargs command
  480.  
  481.       which would result in one or more executions of
  482.  
  483.     command file1 file2 file3 file4 dir1/file1 dir1/file2
  484.  
  485.       Unfortunately this is not a perfectly robust or secure solution.
  486.       Xargs expects its input lines to be terminated with newlines, so
  487.       it will be confused by files with odd characters such as newlines
  488.       in their names.
  489.  
  490. 3.5)  How do I set the permissions on a symbolic link?
  491.  
  492.       Permissions on a symbolic link don't really mean anything.  The
  493.       only permissions that count are the permissions on the file that
  494.       the link points to.
  495.  
  496. 3.6)  How do I "undelete" a file?
  497.  
  498.       Someday, you are going to accidentally type something like
  499.       "rm * .foo", and find you just deleted "*" instead of "*.foo".
  500.       Consider it a rite of passage.
  501.  
  502.       Of course, any decent systems administrator should be doing
  503.       regular backups.  Check with your sysadmin to see if a recent
  504.       backup copy of your file is available.  But if it isn't, read
  505.       on.
  506.  
  507.       For all intents and purposes, when you delete a file with "rm" it
  508.       is gone.  Once you "rm" a file, the system totally forgets which
  509.       blocks scattered around the disk comprised your file.  Even
  510.       worse, the blocks from the file you just deleted are going to be
  511.       the first ones taken and scribbled upon when the system needs
  512.       more disk space.  However, never say never.  It is theoretically
  513.       possible *if* you shut down the system immediately after the "rm"
  514.       to recover portions of the data.  However, you had better have a
  515.       very wizardly type person at hand with hours or days to spare to
  516.       get it all back.
  517.  
  518.       Your first reaction when you "rm" a file by mistake is why not
  519.       make a shell alias or procedure which changes "rm" to move files
  520.       into a trash bin rather than delete them?  That way you can
  521.       recover them if you make a mistake, and periodically clean out
  522.       your trash bin.  Two points:  first, this is generally accepted
  523.       as a *bad* idea.  You will become dependent upon this behaviour
  524.       of "rm", and you will find yourself someday on a normal system
  525.       where "rm" is really "rm", and you will get yourself in trouble.
  526.       Second, you will eventually find that the hassle of dealing with
  527.       the disk space and time involved in maintaining the trash bin, it
  528.       might be easier just to be a bit more careful with "rm".  For
  529.       starters, you should look up the "-i" option to "rm" in your
  530.       manual.
  531.  
  532.       If you are still undaunted, then here is a possible simple
  533.       answer.  You can create yourself a "can" command which moves
  534.       files into a trashcan directory. In csh(1) you can place the
  535.       following commands in the ".login" file in your home directory:
  536.  
  537.     alias can    'mv \!* ~/.trashcan'       # junk file(s) to trashcan
  538.     alias mtcan    'rm -f ~/.trashcan/*'       # irretrievably empty trash
  539.     if ( ! -d ~/.trashcan ) mkdir ~/.trashcan  # ensure trashcan exists
  540.  
  541.       You might also want to put a:
  542.  
  543.     rm -f ~/.trashcan/*
  544.  
  545.       in the ".logout" file in your home directory to automatically
  546.       empty the trash when you log out.  (sh and ksh versions are left
  547.       as an exercise for the reader.)
  548.  
  549.       MIT's Project Athena has produced a comprehensive
  550.       delete/undelete/expunge/purge package, which can serve as a
  551.       complete replacement for rm which allows file recovery.  This
  552.       package was posted to comp.sources.misc (volume 17, issue
  553.       023-026)
  554.  
  555. 3.7)  How can a process detect if it's running in the background?
  556.  
  557.       First of all: do you want to know if you're running in the
  558.       background, or if you're running interactively? If you're
  559.       deciding whether or not you should print prompts and the like,
  560.       that's probably a better criterion. Check if standard input
  561.       is a terminal:
  562.  
  563.         sh: if [ -t 0 ]; then ... fi
  564.         C: if(isatty(0)) { ... }
  565.  
  566.       In general, you can't tell if you're running in the background.
  567.       The fundamental problem is that different shells and different
  568.       versions of UNIX have different notions of what "foreground" and
  569.       "background" mean - and on the most common type of system with a
  570.       better-defined notion of what they mean, programs can be moved
  571.       arbitrarily between foreground and background!
  572.  
  573.       UNIX systems without job control typically put a process into the
  574.       background by ignoring SIGINT and SIGQUIT and redirecting the
  575.       standard input to "/dev/null"; this is done by the shell.
  576.  
  577.       Shells that support job control, on UNIX systems that support job
  578.       control, put a process into the background by giving it a process
  579.       group ID different from the process group to which the terminal
  580.       belongs.  They move it back into the foreground by setting the
  581.       terminal's process group ID to that of the process.  Shells that
  582.       do *not* support job control, on UNIX systems that support job
  583.       control, typically do what shells do on systems that don't
  584.       support job control.
  585.  
  586. 3.8)  Why doesn't redirecting a loop work as intended?  (Bourne shell)
  587.  
  588.       Take the following example:
  589.  
  590.     foo=bar
  591.  
  592.     while read line
  593.     do
  594.         # do something with $line
  595.         foo=bletch
  596.     done < /etc/passwd
  597.  
  598.     echo "foo is now: $foo"
  599.  
  600.       Despite the assignment ``foo=bletch'' this will print
  601.       ``foo is now: bar'' in many implementations of the Bourne shell.
  602.       Why?  Because of the following, often undocumented, feature of
  603.       historic Bourne shells: redirecting a control structure (such as
  604.       a loop, or an ``if'' statement) causes a subshell to be created,
  605.       in which the structure is executed; variables set in that
  606.       subshell (like the ``foo=bletch'' assignment) don't affect the
  607.       current shell, of course.
  608.  
  609.       The POSIX 1003.2 Shell and Tools Interface standardization
  610.       committee forbids the behaviour described above, i.e. in P1003.2
  611.       conformant Bourne shells the example will print ``foo is now:
  612.       bletch''.
  613.  
  614.       In historic (and P1003.2 conformant) implementations you can use
  615.       the following `trick' to get around the redirection problem:
  616.  
  617.     foo=bar
  618.  
  619.     # make file descriptor 9 a duplicate of file descriptor 0 (stdin);
  620.     # then connect stdin to /etc/passwd; the original stdin is now
  621.     # `remembered' in file descriptor 9; see dup(2) and sh(1)
  622.     exec 9<&0 < /etc/passwd
  623.  
  624.     while read line
  625.     do
  626.         # do something with $line
  627.         foo=bletch
  628.     done
  629.  
  630.     # make stdin a duplicate of file descriptor 9, i.e. reconnect
  631.     # it to the original stdin; then close file descriptor 9
  632.     exec 0<&9 9<&-
  633.  
  634.     echo "foo is now: $foo"
  635.  
  636.       This should always print ``foo is now: bletch''.
  637.       Right, take the next example:
  638.  
  639.     foo=bar
  640.  
  641.     echo bletch | read foo
  642.  
  643.     echo "foo is now: $foo"
  644.  
  645.       This will print ``foo is now: bar'' in many implementations,
  646.       ``foo is now: bletch'' in some others.  Why?  Generally each part
  647.       of a pipeline is run in a different subshell; in some
  648.       implementations though, the last command in the pipeline is made
  649.       an exception: if it is a builtin command like ``read'', the
  650.       current shell will execute it, else another subshell is created.
  651.  
  652.       POSIX 1003.2 allows both behaviours so portable scripts cannot
  653.       depend on any of them.
  654.  
  655. 3.9)  How do I run 'passwd', 'ftp', 'telnet', 'tip' and other interactive
  656.       programs from a shell script or in the background?
  657.  
  658.       These programs expect a terminal interface.  Shells makes no
  659.       special provisions to provide one.  Hence, such programs cannot
  660.       be automated in shell scripts.
  661.  
  662.       The 'expect' program provides a programmable terminal interface
  663.       for automating interaction with such programs.  The following
  664.       expect script is an example of a non-interactive version of
  665.       passwd(1).
  666.  
  667.     # username is passed as 1st arg, password as 2nd
  668.     set password [index $argv 2]
  669.     spawn passwd [index $argv 1]
  670.     expect "*password:"
  671.     send "$password\r"
  672.     expect "*password:"
  673.     send "$password\r"
  674.     expect eof
  675.  
  676.       expect can partially automate interaction which is especially
  677.       useful for telnet, rlogin, debuggers or other programs that have
  678.       no built-in command language.  The distribution provides an
  679.       example script to rerun rogue until a good starting configuration
  680.       appears.  Then, control is given back to the user to enjoy the game.
  681.  
  682.       Fortunately some programs have been written to manage the
  683.       connection to a pseudo-tty so that you can run these sorts of
  684.       programs in a script.
  685.  
  686.       To get expect, email "send pub/expect/expect.shar.Z" to
  687.       library@cme.nist.gov or anonymous ftp same from
  688.       durer.cme.nist.gov.
  689.  
  690.       Another solution is provided by the pty 4.0 program, which runs a
  691.       program under a pseudo-tty session and was posted to
  692.       comp.sources.unix, volume 25.  A pty-based solution using named
  693.       pipes to do the same as the above might look like this:
  694.  
  695.     #!/bin/sh
  696.     /etc/mknod out.$$ p; exec 2>&1
  697.     ( exec 4<out.$$; rm -f out.$$
  698.     <&4 waitfor 'password:'
  699.         echo "$2"
  700.     <&4 waitfor 'password:'
  701.         echo "$2"
  702.     <&4 cat >/dev/null
  703.     ) | ( pty passwd "$1" >out.$$ )
  704.  
  705.       Here, 'waitfor' is a simple C program that searches for
  706.       its argument in the input, character by character.
  707.  
  708.       A simpler pty solution (which has the drawback of not
  709.       synchronizing properly with the passwd program) is
  710.  
  711.     #!/bin/sh
  712.     ( sleep 5; echo "$2"; sleep 5; echo "$2") | pty passwd "$1"
  713.  
  714. 3.10) How do I find out the process ID of a program with a particular
  715.       name from inside a shell script or C program?
  716.  
  717.       In a shell script:
  718.  
  719.       There is no utility specifically designed to map between program
  720.       names and process IDs.  Furthermore, such mappings are often
  721.       unreliable, since it's possible for more than one process to have
  722.       the same name, and since it's possible for a process to change
  723.       its name once it starts running.  However, a pipeline like this
  724.       can often be used to get a list of processes (owned by you) with
  725.       a particular name:
  726.  
  727.         ps ux | awk '/name/ && !/awk/ {print $2}'
  728.  
  729.       You replace "name" with the name of the process for which you are
  730.       searching.
  731.  
  732.       The general idea is to parse the output of ps, using awk or grep
  733.       or other utilities, to search for the lines with the specified
  734.       name on them, and print the PID's for those lines.  Note that the
  735.       "!/awk/" above prevents the awk process for being listed.
  736.  
  737.       You may have to change the arguments to ps, depending on what
  738.       kind of Unix you are using.
  739.  
  740.       In a C program:
  741.  
  742.       Just as there is no utility specifically designed to map between
  743.       program names and process IDs, there are no (portable) C library
  744.       functions to do it either.
  745.  
  746.       However, some vendors provide functions for reading Kernel
  747.       memory; for example, Sun provides the "kvm_" functions, and Data
  748.       General provides the "dg_" functions.  It may be possible for any
  749.       user to use these, or they may only be useable by the super-user
  750.       (or a user in group "kmem") if read-access to kernel memory on
  751.       your system is restricted.  Furthermore, these functions are
  752.       often not documented or documented badly, and might change from
  753.       release to release.
  754.